package org.hoyi.ctrls.sys.sh;

import java.io.BufferedReader;
import java.io.Closeable;
import java.io.File;
import java.io.InputStreamReader;

import org.hoyi.DB.ctrl.Console;

/**
 * Shell控制， 检查端口是否占用，关闭端口，执行Shell的方法，
 * 
 * @author sam
 *
 */
public class ShellCtrls {

	/**
	 * 获取操作系统的名称.
	 * 
	 * @return
	 */
	public static String GetOsName() {
		String osName = System.getProperty("os.name");
//		Console.Info("OSNAME:" + osName);
//        if (osName.contains("Mac OS")) {
//            // 苹果
//        } else if (osName.contains("Windows")) {
//            // windows
//        } else {
//            // unix or linux
//        }
		return osName;
	}

	/**
	 * 端口是否占用. 命令使用的lsof,如果本机无lsof命令，请用 yum install lsof安装。
	 * 
	 * @param Port
	 * @return
	 */
	public boolean PortisRuning(int Port) {
		boolean ret_result = false;
		ShellCtrls shs = new ShellCtrls();

		String cmd = "";
		String osname = GetOsName();
		if (osname.toLowerCase().contains("mac os")) {
			cmd = "lsof -i tcp:" + Port;
		} else if (osname.toLowerCase().contains("windows")) {// windows 暂未测试.
			cmd = "netstat -ano|findstr " + Port;
		} else {// linux or unit
			cmd = "netstat -anp |grep " + Port;
		}

		String result = shs.execCmd(cmd, null);
		Console.Info("Port is Running? -> RESULT:" + result);
		ret_result = result.trim().length() > 0;
		return ret_result;
	}

	/**
	 * 停止端口，须关注linux和mac,windows命令区别，当前只在mac测试过 在启动新实例前，直接关闭前实例的端口，也就不需要考虑关闭前端口的问题。
	 * 
	 * 命令使用的lsof,如果本机无lsof命令，请用 yum install lsof安装。
	 * 
	 * @param Port
	 * @return
	 */
	public String StopPort(int Port) {
		String cmd = "";
		String osname = GetOsName();
		String result = "";
		
		ShellCtrls shs = new ShellCtrls();
		if (osname.toLowerCase().contains("windows")) {
			// windows未找到一句命令搞定的，所以做次判断，再kill,如果找到了一句话搞定的，直接用一句话搞定.
			cmd = " netstat -ano | findstr %s";
			cmd = String.format(cmd, Port);
			result = shs.execCmd(cmd, null);
			Console.Info(cmd + ".result:" + result);
			if(result != null) {
				String[] lists = result.split("\n");
				if(lists.length == 0) {
					Console.Info("un opened port.");
				}else if(lists.length > 1) { 
					String pid = gotPID(result, false);
					Console.Info("PID:" + pid);
					cmd = "taskkill /f /t /pid %s";
					cmd = String.format(cmd, pid);
					result = shs.execCmd(cmd, null);
					Console.Info(cmd + ".result:" + result);
				}
			}
		} else {
			if (osname.toLowerCase().contains("mac os")) {
//				cmd = "lsof -i | grep ':%s' | awk '{print $2}' | xargs kill";
//				cmd = "lsof -P | grep ':%s' | awk '{print $2}' | xargs kill -9";
//				String pid = "60974";
//				cmd = "kill /9 " + pid;
				
				cmd = " lsof -t -i tcp:" + Port;
				cmd = String.format(cmd, Port);
				result = shs.execCmd(cmd, null);
				Console.Info(cmd + ".result:" + result);
				if(result != null) {
					String[] lists = result.split("\n");
					if(lists.length == 0) {
						Console.Info("un opened port.");
					}else if(lists.length > 0) { 
						String pid = gotPID(result, true);
						Console.Info("PID:" + pid);
						cmd = "kill -9 %s";
						cmd = String.format(cmd, pid);
						result = shs.execCmd(cmd, null);
						Console.Info(cmd + ".result:" + result);
					}
				}
			} else {// linux or unit
				cmd = "lsof -i :%s | grep 'java' |awk '{print $2}' | xargs kill -9";
			}
			cmd = String.format(cmd, Port);
			result = shs.execCmd(cmd, null);
		}

		return result;
	}
	/**
	 * 根据结果找到PID.
	 * @param _lists
	 * @param ismac 如果是mac要从第二条开始拿参数。linux 可以考虑是否一致.
	 * @return
	 */
	public static String gotPID(String _result, boolean ismac) {
		String pid = "";
		String[] _lists = _result.split("\n");
		if(_lists.length > 0) {
			String lineone = _lists[0];
			if(ismac) {
				pid = lineone.replace("\n", "");
			}else {
				int lastwhite = lineone.lastIndexOf(' ');
				Console.Info("lastwhit.idx:" + lastwhite);
				pid = lineone.substring(lastwhite, lineone.length());
				pid = pid.replace("\n", "");
			}
		}
		
		return pid;
	}

	/**
	 * 执行系统命令, 返回执行结果
	 *
	 * @param cmd 需要执行的命令
	 * @param dir 执行命令的子进程的工作目录, null 表示和当前主进程工作目录相同
	 */
	public static String execCmd(String cmd, File dir) {
		StringBuilder result = new StringBuilder();
		Process process = null;
		BufferedReader bufrIn = null;
		BufferedReader bufrError = null;
		try {
			String osname = GetOsName();
			String cmdexe = "/bin/sh";
			String cmdtype = "-c";

			if (osname.toLowerCase().contains("windows")) {
				cmdexe = "cmd.exe";
				cmdtype = "/c";
			}
			String[] basecmd = { cmdexe, cmdtype, cmd};
//			if(cmd.trim().contains(" ")) {
//				String[] command = cmd.trim().split(" ");
//				basecmd = (String[]) ArrayUtils.addAll(basecmd, command);
//			}else {
//				String[] command = {cmd};
//				basecmd = (String[]) ArrayUtils.addAll(basecmd, command);
//			}

			// 执行命令, 返回一个子进程对象（命令在子进程中执行）
			process = Runtime.getRuntime().exec(basecmd, null, dir);
			// 方法阻塞, 等待命令执行完成（成功会返回0）
			process.waitFor();
			// 获取命令执行结果, 有两个结果: 正常的输出 和 错误的输出（PS: 子进程的输出就是主进程的输入）
			bufrIn = new BufferedReader(new InputStreamReader(process.getInputStream(), "UTF-8"));
			bufrError = new BufferedReader(new InputStreamReader(process.getErrorStream(), "UTF-8"));
			// 读取输出
			String line;
			while ((line = bufrIn.readLine()) != null) {
				result.append(line).append('\n');
			}
			while ((line = bufrError.readLine()) != null) {
				result.append(line).append('\n');
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			closeStream(bufrIn);
			closeStream(bufrError);
			// 销毁子进程
			if (process != null) {
				process.destroy();
			}
			// 返回执行结果
			return result.toString();
		}
	}
	/**
	 * 关闭流
	 *
	 * @param stream
	 */
	private static void closeStream(Closeable stream) {
		if (stream != null) {
			try {
				stream.close();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}
}

